#!/usr/bin/perl

use strict;
use Getopt::Std;
use File::Basename;
use Time::HiRes qw(time);
use List::Util qw(sum max);

my $opts = {};
getopts('l', $opts);

my %type_map = (
    nyu => 'nyu ',
    pl  => 'perl ',
    py  => 'python ',
    rb  => 'ruby ',
    php => 'php ',
    js  => 'js ',
    lua => 'lua ',
    pike => 'pike ',
    nut => 'sq ',
    ml => 'ocaml ',
    tcl => 'tclsh ',
    awk => 'awk -f ',
    tle => 'turtle ',
    rbt => 'rabbit ',
    vbs => 'cscript /nologo ',
    nako => 'cnako ',
    exe => './',
);
my $typep = join('|', keys %type_map);

my $dir = dirname(__FILE__);
my @list = grep {
    $_ ne __FILE__ && basename($_) !~ /^\./ && !/~$/ && /\.(${typep})$/
} <$dir/*.*>;

my %names = ();
foreach my $file (@list) {
    my ($name, $d, $ext) = fileparse($file, qr/\.[^\.]*/);
    $name =~ s/\.(.*)$//;
    my $lang = $1;
    $ext =~ s/^\.//;
    push(@{$names{$name}}, {path=>$file, name=>$name, ext=>$ext, lang=>$lang});
}

if ($opts->{'l'}) {
    # list print mode

    my %langs = ();
    foreach my $vals (values %names) {
        foreach my $val (@$vals) {
            $langs{$val->{lang}||$val->{ext}}++;
        }
    }

    my @langs = sort keys %langs;
    my $max_langs_len = max(map {length($_)} @langs);
    my $max_name_len = max(map {length($_)} keys %names);
    my @langs2 = map {
        [split(//, (' ' x ($max_langs_len - length($_))) . $_)];
    } @langs;
    for (my $i = 0; $i < $max_langs_len; $i++) {
        print '|', (' ' x ($max_name_len + 2)), '|';
        print join('|', map {$_->[$i]} @langs2), "|\n";
    }

    print '|', ('-' x ($max_name_len + 2)), '|';
    print join('-', map {'-'} @langs2), "|\n";

    foreach my $name (sort keys %names) {
        print "| $name", (' ' x ($max_name_len - length($name))), " |";

        my $h = {};
        foreach my $val (@{$names{$name}}) {
            $h->{$val->{lang}||$val->{ext}}++;
        }

        print join('|', map {$h->{$_} ? 'o' : 'x'} @langs), "|\n";
    }

    exit(0);
}

my $total_delays = {};

my @execs = @ARGV ? @ARGV : (sort keys %names);
foreach my $name (@execs) {
    print "== $name ==\n";
    my $delays = [];
    foreach my $target (@{$names{$name}}) {
        my $prg = $type_map{$target->{ext}} || next;
        my $cmd = "$prg$target->{path}";
        print "* $cmd\n";
        my $start = time();
        my $res = `$cmd`;
        my $delay = time() - $start;
        if ($? == 0) {
            push(@$delays, {ext => $target->{lang}||$target->{ext}, delay => $delay});
            push(@{$total_delays->{$target->{lang}||$target->{ext}}}, $delay);
        } else {
            push(@$delays, {ext => $target->{ext}, delay => 'FAILED'});
        }
        print "RET=$?, TIME=$delay\n";
        print "---\n";
        print "$res";
        print "---\n";
        print "\n";
    }

    print "== $name:RANKING ==\n";
    foreach my $d (sort {
        if ($a->{delay} eq 'FAILED') {
            if ($b->{delay} eq 'FAILED') {
                0;
            } else {
                1;
            }
        } elsif ($b->{delay} eq 'FAILED') {
            -1;
        } else {
            $a->{delay} <=> $b->{delay}
        }
                   } @$delays) {
        printf("%5s: %s\n", $d->{lang}||$d->{ext}, $d->{delay});
    }
    print "\n";
}

my $total_delays_avg = [];
foreach my $key (keys %{$total_delays}) {
    my $val = $total_delays->{$key};
    my $avg = sum(@$val) / scalar(@$val);
    push(@$total_delays_avg, {ext => $key, delay => $avg});
}

print "== Total:RANKING ==\n";
foreach my $d (sort {$a->{delay} <=> $b->{delay}} @$total_delays_avg) {
    printf("%5s: %s\n", $d->{ext}, $d->{delay});
}
print "\n";

1;
